package xin.shaozeming.base.common.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.*;
import lombok.extern.log4j.Log4j2;
import org.bytedeco.javacpp.opencv_core;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.bytedeco.javacv.Frame;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author: 邵泽铭
 * @date: 2018/10/25
 * @description:
 **/

@Log4j2
public class AliUploadUtils {

    private String uploadPath;// 临时文件目录
    private static final String ACCESS_KEY = "";
    private static final String ACCESS_SECRET = "";
    private static final String BUCKET_NAME = "";
    private static final String END_POINT = "oss-cn-beijing.aliyuncs.com";
    private static final String DOMAIN = "";


    /**
     * 上传文件
     *
     * @param file
     * @return true 上传成功 false上传失败
     */
    public static Map<String, Object> upload(MultipartFile file, String path) {
        String type = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1, file.getOriginalFilename().length());
        try {
            return uploadStream(file.getInputStream(), path, type);
        } catch (IOException e) {
            log.error("upload 上传失败:{}", e.getMessage());
            Map<String, Object> map = new HashMap<>();
            map.put("error", true);
            return map;
        }
    }


//    /**
//     * 断点续传
//     *
//     * @param file
//     * @return true 上传成功 false上传失败
//     */
//    public static Map<String, Object> upload(MultipartFile file,String uploadId,Integer index,Integer size, String path,boolean isOver) {
//        // 创建OSSClient实例。
//        OSSClient ossClient = new OSSClient(END_POINT, ACCESS_KEY, ACCESS_SECRET);
//
//        if(StringUtils.isEmpty(uploadId)){
//            // 创建InitiateMultipartUploadRequest对象。
//            InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(BUCKET_NAME, file.getOriginalFilename());
//            // 初始化分片。
//            InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
//            // 返回uploadId，它是分片上传事件的唯一标识，您可以根据这个ID来发起相关的操作，如取消分片上传、查询分片上传等。
//             uploadId = upresult.getUploadId();
//        }
//
//        UploadPartRequest uploadPartRequest = new UploadPartRequest();
//        uploadPartRequest.setBucketName(BUCKET_NAME);
//        uploadPartRequest.setKey(file.getOriginalFilename());
//        uploadPartRequest.setUploadId(uploadId);
//        try {
//            uploadPartRequest.setInputStream(file.getInputStream());
//        } catch (IOException e) {
//            log.error("分片上传失败 :{}",e.getMessage() );
//        }
//        // 设置分片大小。除了最后一个分片没有大小限制，其他的分片最小为100KB。
//        uploadPartRequest.setPartSize(size);
//        // 设置分片号。每一个上传的分片都有一个分片号，取值范围是1~10000，如果超出这个范围，OSS将返回InvalidArgument的错误码。
//        uploadPartRequest.setPartNumber( index);
//        // 每个分片不需要按顺序上传，甚至可以在不同客户端上传，OSS会按照分片号排序组成完整的文件。
//        UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
//
//        if(isOver){
//            // 创建CompleteMultipartUploadRequest对象。
//              // 在执行完成分片上传操作时，需要提供所有有效的partETags。OSS收到提交的partETags后，会逐一验证每个分片的有效性。当所有的数据分片验证通过后，OSS将把这些分片组合成一个完整的文件。
//            CompleteMultipartUploadRequest completeMultipartUploadRequest =
//                    new CompleteMultipartUploadRequest(BUCKET_NAME, file.getOriginalFilename(), uploadId, partETags);
//
//           // 如果需要在完成文件上传的同时设置文件访问权限，请参考以下示例代码。
//             // completeMultipartUploadRequest.setObjectACL(CannedAccessControlList.PublicRead);
//
//              // 完成上传。
//            CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
//
//             // 关闭OSSClient。
//            ossClient.shutdown();
//        }
//    }


    /**
     * 上传base64文件
     *
     * @param base64
     * @return true 上传成功 false上传失败
     */
    public static Map<String, Object> upload(String base64, String path) {

        byte[] decode =  Base64Utils.Base64ToByte(base64);
        ByteArrayInputStream inputStream = new ByteArrayInputStream(decode);
        try {
            return uploadStream(inputStream, path, base64.substring(base64.indexOf("/")+1, base64.indexOf(";")));
        } catch (Exception e) {
            log.error("upload 上传失败:{}", e.getMessage());
            Map<String, Object> map = new HashMap<>();
            map.put("error", true);
            return map;
        }
    }

    /**
     * 上传文件流
     *
     * @param inputStream
     * @return true 上传成功 false上传失败
     */
    private static Map<String, Object> uploadStream(InputStream inputStream, String path, String type) {
        String fileName = path + ToolsUtils.getUUID() + "." + type;
        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(END_POINT, ACCESS_KEY, ACCESS_SECRET);
        ossClient.putObject(BUCKET_NAME, fileName, inputStream);
        // 关闭OSSClient。
        ossClient.shutdown();
        Map<String, Object> map = new HashMap<>();
        map.put("error", false);
        map.put("path", DOMAIN + fileName);
        return map;
    }


    public static void deletePic(List<String> list) {
        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(END_POINT, ACCESS_KEY, ACCESS_SECRET);
        // 删除文件。
        DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(BUCKET_NAME).withKeys(list));
        List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();

        /*部分失败再重试一遍*/
        if (deletedObjects.size() < list.size()) {
            list.removeAll(deletedObjects);
            DeleteObjectsResult result = ossClient.deleteObjects(new DeleteObjectsRequest(BUCKET_NAME).withKeys(list));
        }
        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /**
     * 上传视频
     *
     * @param file
     * @return true 上传成功 false上传失败
     */
    public static Map<String, Object> uploadVideo(MultipartFile file, String path) {

        Map<String, Object> upload = upload(file, path);
        if (!(Boolean) upload.get("error")) {
            try {
                String videoPath = upload.get("path").toString();
                String name= videoPath.substring(videoPath.lastIndexOf("/")+1, videoPath.length());
                upload.put("name",name );
                grabberVideoFramer(file.getInputStream(),path, upload);

            } catch (IOException e) {
                log.error("upload 上传视频失败:{}", e.getMessage());
            }
        }


        return upload;
    }


    private static void grabberVideoFramer(InputStream video,String path, Map<String,Object> map) {

        //最后获取到的视频的图片的路径
        String pivStr = "";
        //Frame对象
//        Frame frame = null;
        //标识
        int flag = 0;
        try {
            Frame frame=null;
            FFmpegFrameGrabber fFmpegFrameGrabber = new FFmpegFrameGrabber(video);
            fFmpegFrameGrabber.start();
            //获取视频总帧数
            int ftp = fFmpegFrameGrabber.getLengthInFrames();
            String rotate = fFmpegFrameGrabber.getVideoMetadata("rotate");
            while (flag <= ftp) {

                frame  = fFmpegFrameGrabber.grabImage();
                opencv_core.IplImage src = null;

                if (frame != null && flag == 1) {
                    // 视频旋转调整
                    if (!StringUtils.isEmpty(rotate)) {
                        OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
                        src = converter.convert(frame);
                        frame = converter.convert(rotate(src, Integer.valueOf(rotate)));
                    }

                    BufferedImage bufferedImage = FrameToBufferedImage(frame);
                    int width = bufferedImage.getWidth();
                    int height = bufferedImage.getHeight();


                    // 图片大小限制
                    if (width > height) {
                        // 高宽比
                        double proportion = (double) height / (double) width;
                        width = 600;
                        BigDecimal bd = new BigDecimal(width * proportion).setScale(0, BigDecimal.ROUND_HALF_UP);
                        height = bd.intValue();
                    }

                    // 图片压缩
                    BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
                    bi.getGraphics().drawImage(bufferedImage.getScaledInstance(width, height, Image.SCALE_SMOOTH),
                            0, 0, null);


                    InputStream inputStream = bufferedImageToInputStream(bi);
                    Map<String, Object> jpgMap = uploadStream(inputStream, path, "jpg");
                    if (!(Boolean) jpgMap.get("error")) {
                        map.put("coverPath",jpgMap.get("path") );
                    }

                    break;
                }
                flag++;
            }

            fFmpegFrameGrabber.stop();
            fFmpegFrameGrabber.close();
        } catch (Exception e) {
            log.error("upload grabberVideoFramer 异常:{}", e.getMessage());
        }

    }

    private static BufferedImage FrameToBufferedImage(Frame frame) {
        //创建BufferedImage对象
        Java2DFrameConverter converter = new Java2DFrameConverter();
        return converter.getBufferedImage(frame);
    }

    private static opencv_core.IplImage rotate(opencv_core.IplImage src, int rotate) {
        opencv_core.IplImage img = opencv_core.IplImage.create(src.height(), src.width(), src.depth(), src.nChannels());
        opencv_core.cvTranspose(src, img);
        opencv_core.cvFlip(img, img, rotate);
        return img;
    }

    /**
     * 将BufferedImage转换为InputStream
     *
     * @param image
     * @return
     */
    private static InputStream bufferedImageToInputStream(BufferedImage image) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, "jpg", os);
            return new ByteArrayInputStream(os.toByteArray());
        } catch (IOException e) {
            log.error("upload 提示:{}", e.getMessage());
        }
        return null;
    }


}
